package com.cyy.controller

import cn.hutool.core.io.FileUtil
import cn.hutool.system.SystemUtil
import com.jfinal.kit.Kv
import com.jfinal.kit.StrKit
import com.jfinal.plugin.activerecord.generator.MetaBuilder
import com.jfinal.template.Engine
import com.jfinal.template.Template
import java.io.File
import java.io.FileWriter
import java.util.*
import javax.sql.DataSource
import javax.swing.filechooser.FileSystemView

class CyyGenerator(val ds:DataSource, val engine:Engine, val metaBuilder:MetaBuilder,val baseTemplatePath:String) {
    // 文件分隔符（在 UNIX 系统中是“/”）
    private val fileSeparator = SystemUtil.get(SystemUtil.FILE_SEPARATOR)

    val tableMetas=metaBuilder.build()

    /**
     * 执行本 代码生成器的主要任务
     * @throws Exception
     */
    @Throws(Exception::class)
    fun doTask(content: Kv){
        val metas = ArrayList<Map<String, Any>>()
        val templates = arrayOf("controller.html", "service.html", "serviceImpl.html", "dao.html", "basedao.html", "vo.html", "crud.txt")
        val fileNames = arrayOf("Controller.java", "Service.java", "ServiceImpl.java", ".java", ".java", "VO.java",".kt")
        val paths = arrayOf("controller", "service", "service/impl", "model", "model/base", "vo","crud")

        for (i in templates.indices) {
            templates[i] = "java/" + templates[i]
        }

        for (table in tableMetas) {
            val claLowName = StrKit.firstCharToLowerCase(StrKit.toCamelCase(table.modelName))
            val claUpName = StrKit.firstCharToUpperCase(StrKit.toCamelCase(table.modelName))
            val meta = HashMap<String, Any>()
            meta["cols"] = table.columnMetas
            meta["claUpName"] = claUpName
            meta["claLowName"] = claLowName
            meta["tableName"] = table.name
            content["remarks"] = table.remarks
            content["meta"] = meta
            content["table"] = table
            content["cols"] = table.columnMetas
            content["claUpName"] = claUpName
            content["claLowName"] = claLowName
            content["tableName"] = table.name
            for (i in templates.indices) {
                val template = engine.getTemplate(templates[i])
                // 模板为basedao时做特殊处理,可以去掉
                var fileName: String
                if ("java/basedao.html" == templates[i]) {
                    fileName = toOutJavaPath(paths[i], content) + "Base" + table.modelName + fileNames[i]
                } else {
                    fileName = toOutJavaPath(paths[i], content) + table.modelName + fileNames[i]
                }
                writeFiles(template, content, fileName, false)
            }
            metas.add(meta)

            //生成 每张表的sql 文件
            writeFiles(engine.getTemplate("sql/table_sql.html"), content, toOutResourcesPath("sql", content) + "/" + claLowName + ".sql", true)
            //生成html
            //toOutWEBINF("pages/"+rootRoute+"/"+claLowName);
            writeFiles(engine.getTemplate("view/model/index.html"), content, toOutWEBINF("pages/" + content["rootRoute"].toString() + "/" + claLowName, content) + "index.html", true)
            writeFiles(engine.getTemplate("view/model/detail.html"), content, toOutWEBINF("pages/" + content["rootRoute"].toString() + "/" + claLowName, content) + "detail.html", true)
            writeFiles(engine.getTemplate("view/model/_form.html"), content, toOutWEBINF("pages/" + content["rootRoute"].toString() + "/" + claLowName, content) + "_form.html", true)
        }
        content["metas"] = metas

        //生成附加java文件
        genJava(content)
        //生成sql-all文件
        genAllSql(content)
        // mapping 映射
        genMapping(content)
        // 生成路由
        genRoutes(content)
        // 继续拓展 生成 config
        genConfig(content)
        // web.xml
        genWebXml(content)
        // config_dev.properties
        genDevConfig(content)
        // config_pro.properties
        genProConfig(content)
        // pom.xml
        gengPom(content)
        //page /comm layout_admin.html
//        writeFiles(engine.getTemplate("generator/view/comm/layout_admin.html"), content, toOutWEBINF("pages/comm", content) + "/layout_admin.html", true)
        writeFiles(engine.getTemplate("view/comm/layout_admin.html"), content, toOutWEBINF("pages/comm", content) + "layout_admin.html", true)
        // ------------------------------------- copy resources ----------------------------------------
        println("------------ copy resources --------")
        FileUtil.copy(baseTemplatePath+"/view/index", toOutWEBINF("pages/" + content["rootRoute"].toString(), content), false)
        FileUtil.copy(baseTemplatePath+"/view/assets", toOutWebApp("", content), false)

//        FileUtil.copy("view/index", toOutWEBINF("pages/" + content["rootRoute"].toString(), content), false)
//        FileUtil.copy("view/assets", toOutWebApp("", content), false)

        println("------------ ok 刷新项目  --------")
    }

    /**
     * 生成代码文件
     * @param template
     * @param context
     * @param fileName
     * @param doPrint
     * @throws Exception
     */
    @Throws(Exception::class)
    fun writeFiles(template: Template, context: Kv, fileName: String, doPrint: Boolean) {
        val fileWriter = FileWriter(fileName, false)
        template.render(context, fileWriter)
        fileWriter.close()
        if (doPrint) {
            println("write File: $fileName")
        }
    }

    /**
     * 生成到桌面
     *
     * @return
     */
    fun toDesktop(): String {
        val fsv = FileSystemView.getFileSystemView()
        val com = fsv.homeDirectory // 这便是读取桌面路径的方法了
        return com.path + "/"
    }

    /**
     * 输出src/main/java - 包 -路径下
     *
     * @param out
     * @return
     */
    fun toOutJavaPath(out: String, content: Kv): String {
        val outPath = (toDesktop() + content["projectName"] + "/" + content["baseSrcPath"]
                + content["projectPackage"].toString().replace(".", fileSeparator) + "/" + out + "/")

        existFileSys(outPath)
        return outPath
    }

    /**
     * 检查创建文件
     *
     * @param outPath
     * @return
     */
    fun existFileSys(outPath: String): Boolean {
        val file = File(outPath)
        if (!file.exists()) {
            file.mkdirs()
        }
        return true
    }

    /**
     * 输出到resources目录下 TODO 待实现
     *
     * @param out
     * @return
     */
    fun toOutResourcesPath(out: String, content: Kv): String {
        val outPath = toDesktop() + content["projectName"] + "/" + content["baseResourcesPath"] + out
        existFileSys(outPath)
        return outPath
    }

    /**
     * 输出到webapp目录下 TODO 待完成
     *
     * @param out
     * @return
     */
    fun toOutWebApp(out: String, content: Kv): String {
        val outPath = toDesktop() + content["projectName"] + "/" + content["baseWebAppPath"] + out
        existFileSys(outPath)
        return outPath
    }

    /**
     * 输出到WEB-INF目录下
     *
     * @param out
     * @return
     */
    fun toOutWEBINF(out: String, content: Kv): String {
        val outPath = toDesktop() + content["projectName"] + "/" + content["baseWEBINFPath"] + out + "/"
        existFileSys(outPath)
        return outPath
    }

    /**
     * 输出java路径下
     *
     * @param out
     * @return
     */
    fun toOutSrcPath(out: String, content: Kv): String {
        val outPath = toDesktop() + content["projectName"] + "/" + out
        existFileSys(outPath)
        return outPath
    }

    fun build( metas: Kv) {
        try {
            println("开始执行模板渲染,生成文件...")
            doTask( metas)
            println("执行模板渲染,生成文件结束...")
        } catch (e: Exception) {
            e.printStackTrace()
            println("生成失败,程序结束...")
        }
    }

    /**
     * 生成mapping
     * @param content
     */
    private fun genMapping(content: Kv) {
        try {
            writeFiles(engine.getTemplate("java/_MappingKit.html"), content, toOutJavaPath("model", content) + "_MappingKit.java", true)
        } catch (e: Exception) {
            println("--- _MappingKit生成失败 ---")
            e.printStackTrace()
        }

    }

    /**
     * 生成config_pro.properties配置文件
     */
    private fun genProConfig(content: Kv) {
        try {
            writeFiles(engine.getTemplate("config_dev.html"), content, toOutResourcesPath("", content) + "config_pro.properties", true)
        } catch (e: Exception) {
            println("--- config_dev.propertis生成失败 ---")
            e.printStackTrace()
        }

    }

    /**
     * 生成config_dev.properties配置文件
     */
    private fun genDevConfig(content: Kv) {
        try {
            writeFiles(engine.getTemplate("config_pro.html"), content, toOutResourcesPath("", content) + "config_dev.properties", true)
        } catch (e: Exception) {
            println("--- config_pro.propertis生成失败 ---")
            e.printStackTrace()
        }

    }

    /**
     * 生成web.xml
     */
    private fun genWebXml(content: Kv) {
        try {
            writeFiles(engine.getTemplate("web.html"), content, toOutWEBINF("", content) + "web.xml", true)
        } catch (e: Exception) {
            println("--- web.xml生成失败 ---")
            e.printStackTrace()
        }

    }

    /**
     * 生成pom文件
     * @param content
     */
    private fun gengPom(content: Kv) {
        try {
            writeFiles(engine.getTemplate("pom.html"), content, toOutSrcPath("", content) + "pom.xml", true)
        } catch (e: Exception) {
            println("--- pom.xml生成失败 ---")
            e.printStackTrace()
        }

    }

    /**
     * 生成config
     */
    private fun genConfig(content: Kv) {
        try {
            writeFiles(engine.getTemplate("java/config.html"), content,
                    toOutJavaPath("", content) + content["projectFilterName"] + "Config.java", true)
        } catch (e: Exception) {
            println("--- config.java生成失败 ---")
            e.printStackTrace()
        }

    }

    /**
     * 路由 映射
     */
    private fun genRoutes(content: Kv) {
        try {
            writeFiles(engine.getTemplate("java/AdminRoutes.html"), content,
                    toOutJavaPath("", content) + StrKit.firstCharToUpperCase(content["rootRoute"].toString()) + "Routes.java", true)
        } catch (e: Exception) {
            println("--- 路由生成失败 ---")
            e.printStackTrace()
        }

    }

    /**
     * 生成all_sqls.sql 文件
     * @param content
     * @param engine
     */
    private fun genAllSql(content: Kv) {
        try {
            writeFiles(engine.getTemplate("sql/all_sqls.html"), content, toOutResourcesPath("sql", content) + "/all_sqls.sql", true)
        } catch (e: Exception) {
            println("--- sql文件生成失败 ---")
            e.printStackTrace()
        }

    }

    /**
     * 生成附加java文件
     * @param content
     * @param engine
     */
    private fun genJava(content: Kv) {
        try {
            writeFiles(engine.getTemplate("java/ParamsUtils.html"), content, toOutJavaPath("comment/utils", content) + "/ParamsUtils.java", true)
            writeFiles(engine.getTemplate("java/ResultData.html"), content, toOutJavaPath("comment/utils", content) + "/ResultData.java", true)
            writeFiles(engine.getTemplate("sql/FieldDirective.html"), content, toOutJavaPath("comment/directive", content) + "/FieldDirective.java", true)
            writeFiles(engine.getTemplate("java/IndexController.html"), content, toOutJavaPath("controller", content) + "/IndexController.java", true)
        } catch (e: Exception) {
            println("--- 附加java文件生成失败 ---")
            e.printStackTrace()
        }
    }
}